package com.yb.bluetooth.normal

import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothServerSocket
import android.bluetooth.BluetoothSocket
import com.blankj.utilcode.util.ThreadUtils
import timber.log.Timber
import java.io.IOException
import java.util.*
import java.util.concurrent.ConcurrentHashMap

/**
 * Created by zyb
 * Date 2021/11/24 17:44
 * Desc 传统蓝牙服务
 */

internal object BtService {

    private lateinit var mUUID: UUID
    private var mReceiveListener: ((BluetoothDevice, String) -> Unit)? = null
    private var mStatusListener: ((BluetoothDevice, BtAction, Exception?) -> Unit)? = null
    private const val TAG = "BtService"
//    private val TEST_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66")
    private var mServerSocket: BluetoothServerSocket? = null
    private val mPool = ThreadUtils.getCachedPool()
    private var mIsAccept = false
    private val mBtMap = ConcurrentHashMap<String, BluetoothSocket?>()

    fun init(uuid: UUID){
        mUUID = uuid
    }

    /**
     * 启动服务
     *
     * @param name 服务的可识别名称
     * @param keep 是否保持开放服务，默认只接收一次连接就关闭
     */
    fun start(name: String, keep: Boolean = false) {
        close()
        mIsAccept = true
        mServerSocket = BtUtils.mBluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(name, mUUID)
        mPool.execute {
            do {
                while (mIsAccept) {
                    try {
                        mServerSocket?.accept()
                    } catch (e: IOException) {
                        Timber.tag(BtUtils.TAG).d(e, "socket的accept（）方法失败")
                        try {
                            mServerSocket?.close()
                        } catch (e: IOException) {
                            Timber.tag(BtUtils.TAG).e(e, "关闭ServerSocket失败")
                        }
                        break
                    }?.also {
                        connected(it)
                    }
                }
            } while (keep && mIsAccept)
        }
    }

    /**
     * 关闭服务
     */
    fun close() {
        mIsAccept = false
        try {
            mServerSocket?.close()
        } catch (e: IOException) {
            Timber.tag(BtUtils.TAG).e(e, "关闭ServerSocket失败")
        }
    }

    /**
     * 发送消息
     *
     * @param address 目标设备的mac地址
     * @param data 数据
     * @param callback 结果回调
     */
    fun send(address: String, data: ByteArray, callback: ((Boolean) -> Unit)? = null) {
        val socket = mBtMap[address]
        if (socket == null) {
            Timber.tag(TAG).e("未获取到设备mac地址为 $address 的socket，发送消息失败")
            callback?.invoke(false)
            return
        }
        if (!socket.isConnected) {
            Timber.tag(TAG).e("未连接到设备mac地址为 $address 的socket，发送消息失败")
            callback?.invoke(false)
            return
        }
        mPool.execute {
            try {
                socket.outputStream.write(data)
                Timber.tag(TAG).d("发送到设备mac地址为 $address 的消息成功")
                callback?.let { ThreadUtils.runOnUiThread { it.invoke(true) } }
            } catch (e: IOException) {
                callback?.let { ThreadUtils.runOnUiThread { it.invoke(false) } }
                Timber.tag(TAG).e(e, "发送到设备mac地址为 $address 的消息失败")
            }
        }
    }

    fun connect(device: BluetoothDevice) {
        mPool.execute {
            BtUtils.cancelScanDevice()
            val socket = device.createRfcommSocketToServiceRecord(mUUID)
            try {
                socket.connect()
            } catch (e: IOException) {
                Timber.tag(TAG).e(e, "连接失败-> deviceName：${device.name}")
                ThreadUtils.runOnUiThread {
                    mStatusListener?.invoke(device, BtAction.STATE_CONNECT_FAILED, e)
                }
                return@execute
            }
            connected(socket)
        }
    }

    fun disconnect(address: String) {
        val socket = mBtMap[address] ?: return Timber.tag(TAG).e("未获取到设备mac地址为 $address 的socket，断开连接失败")
        try {
            socket.close()
        } catch (e: IOException) {
            Timber.tag(BtUtils.TAG).e(e, "关闭bluetoothSocket失败")
        }
    }

    fun isConnected(address: String): Boolean {
        val socket = mBtMap[address]
        return socket != null && socket.isConnected
    }


    fun setBtListener(state: ((BluetoothDevice, BtAction, Exception?) -> Unit)? = null,
                      receive: ((BluetoothDevice, String) -> Unit)? = null) {
        mStatusListener = state
        mReceiveListener = receive
    }


    private fun connected(socket: BluetoothSocket) {
        val device = socket.remoteDevice
        ThreadUtils.runOnUiThread { mStatusListener?.invoke(device, BtAction.STATE_CONNECT, null) }
        Timber.tag(TAG).d("已连接-> deviceName：${device.name}；deviceAddress：${device.address}")
        mBtMap[socket.remoteDevice.address] = socket
        mPool.execute {
            receiveMessage(socket)
        }
    }

    private fun receiveMessage(socket: BluetoothSocket) {
        val inputStream = socket.inputStream
        val buffer = ByteArray(1024)
        val device = socket.remoteDevice
        val name = device.name
        var numBytes: Int
        while (true) {
            numBytes = try {
                inputStream.read(buffer)
            } catch (e: IOException) {
                ThreadUtils.runOnUiThread { mStatusListener?.invoke(device,
                    BtAction.STATE_DISCONNECT, e) }
                Timber.tag(TAG).d(e, "设备 $name 断开连接")
                mBtMap.remove(device.address)
                break
            }
            val message = String(buffer, 0, numBytes)
            Timber.tag(TAG).d("接收到设备 $name 的消息：${message}")
            ThreadUtils.runOnUiThread { mReceiveListener?.invoke(device, message) }
        }
    }


}